/**
 * this class handle the CRUD operations in mongo db for EventLog
 */
package co.edu.unal.satacredito.database.dao;

import co.edu.unal.satacredito.database.entity.EventLog;
import co.edu.unal.satacredito.database.entity.Machine;
import co.edu.unal.satacredito.database.entity.exceptions.NonexistentEntityException;
import co.edu.unal.satacredito.database.entity.exceptions.NullFieldEntityException;
import co.edu.unal.satacredito.database.entity.exceptions.PreexistingEntityException;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Key;
import com.google.code.morphia.query.Query;
import com.google.code.morphia.query.UpdateOperations;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bson.types.ObjectId;

/**
 *
 * @author dfalfonsoc
 * @version 1.0
 *
 *
 */
public class EventLogMongoDao {

    private Datastore ds;

    public EventLogMongoDao(Datastore ds) {
        this.ds = ds;
        this.ds.ensureIndexes();
    }

    public Datastore getDatastore() {
        return ds;
    }

    public ObjectId create(EventLog eventLog) throws PreexistingEntityException {
        try {
            Query <EventLog> q= ds.find(EventLog.class);
            q.field("machine").equal(eventLog.getMachine());
            q.field("work").equal(eventLog.getWork());
            q.field("stateWork").equal(eventLog.getStateWork());
            q.field("startDate").equal(eventLog.getStartDate());
            q.field("endDate").equal(eventLog.getEndDate());
            q.field("fileCheck").equal(eventLog.getFileCheck());
            EventLog event=q.get();
            if (event != null) {
                throw new PreexistingEntityException("The event log with file check '"
                    + eventLog.getFileCheck() + "' couldn't be created. Already exist.");
            }
            Key<EventLog> key = ds.save(eventLog);
            ObjectId id=(ObjectId) key.getId();
            return (ObjectId) key.getId();
        } catch (PreexistingEntityException pee) {
            Logger.getLogger(EventLog.class.getName()).log(Level.SEVERE, null, pee);
            return null;
        }
    }

    public void update(ObjectId id, EventLog newEventLog) throws
            NonexistentEntityException, PreexistingEntityException, NullFieldEntityException, Exception {
        try {
            Query q = ds.createQuery(EventLog.class).field("_id").equal(id);
            UpdateOperations<EventLog> ops = null;
            try {
                ops = ds.createUpdateOperations(EventLog.class).set("machine", newEventLog.getMachine()).set("work", newEventLog.getWork()).set("stateWork", newEventLog.getStateWork()).set("startDate", newEventLog.getStartDate()).set("endDate", newEventLog.getEndDate()).set("fileCheck", newEventLog.getFileCheck());
            } catch (Exception e) {
                throw new NullFieldEntityException("the event log with id '"
                        + id.toString() + "' have null fields.");
            }
            ds.update(q, ops);
        } catch (Exception e) {
            if (e.getClass().equals(PreexistingEntityException.class)) {
                throw e;
            } else if (e.getClass().equals(NullFieldEntityException.class)) {
                throw e;
            } else {
                throw new NonexistentEntityException("The event log with id '"
                        + id.toString() + "' couldn't be updated. May no longer exist");
            }
        }

    }

    public void delete(ObjectId id) throws NonexistentEntityException {
        try {
            Query q = ds.createQuery(EventLog.class).field("_id").equal(id);
            ds.delete(q);
        } catch (Exception e) {
            throw new NonexistentEntityException("The event log with the id '"
                    + id.toString() + "' couldn't be deleted. May no longer exist.");
        }
    }

    public List<EventLog> findAll() throws NonexistentEntityException {
        try {
            List<EventLog> list = ds.find(EventLog.class).asList();
            return list;
        } catch (Exception e) {
            throw new NonexistentEntityException("The database "
                    + ds.getMongo().getUsedDatabases()
                    + " at " + ds.getMongo().getAddress()
                    + " don't contain any element of the 'Event log' type ");
        }
    }

    public EventLog findById(ObjectId id) throws NonexistentEntityException, Exception {
        try {
            Query q = ds.createQuery(EventLog.class).field("_id").equal(id);
            if (q.countAll() == 0) {
                throw new NonexistentEntityException("The brand with name '"
                        + id + "' couldn't be find. May no longer exist");
            } else {
                EventLog br = (EventLog) q.get();
                return br;
            }
        } catch (Exception e) {
            throw e;
        }
    }

    public List<EventLog> findByMachine(Machine machine) throws Exception, NonexistentEntityException {
        try {
            Query<EventLog> q = ds.createQuery(EventLog.class).filter("machine =", machine);
            List<EventLog> list = q.asList();
            if (list.isEmpty()) {
                throw new NonexistentEntityException("Not exist log entries with the machine '"
                        + machine.getMachineName() + "' .");
            } else {
                return list;
            }
        } catch (Exception e) {
            throw e;
        }
    }

    public List<EventLog> findByWork(String work) throws NonexistentEntityException {
        try {
            Query q = ds.createQuery(EventLog.class).field("work").equal(work);
            List list = q.asList();
            return list;
        } catch (Exception e) {
            throw new NonexistentEntityException("The database "
                    + ds.getMongo().getUsedDatabases()
                    + " at " + ds.getMongo().getAddress()
                    + " don't contain any element with work" + work);
        }
    }

    public List<EventLog> findByStateWork(int stateWork) throws NonexistentEntityException {
        try {
            Query q = ds.createQuery(EventLog.class).field("stateWork").equal(stateWork);
            List list = q.asList();
            return list;
        } catch (Exception e) {
            throw new NonexistentEntityException("The database "
                    + ds.getMongo().getUsedDatabases()
                    + " at " + ds.getMongo().getAddress()
                    + " don't contain any machine whit the status " + stateWork);
        }
    }

    public List<EventLog> findByDate(Date initDate, Date endDate) throws NonexistentEntityException {
        try {
            Query<EventLog> q = ds.createQuery(EventLog.class).filter("startDate >=", initDate).filter("endDate <=", endDate);
            List<EventLog> list = q.asList();
            return list;
        } catch (Exception e) {
            throw new NonexistentEntityException("The database "
                    + ds.getMongo().getUsedDatabases()
                    + " at " + ds.getMongo().getAddress()
                    + " don't contain any element of with the time period between "
                    + initDate.toString() + " and " + endDate.toString());
        }
    }

    public EventLog findByfileCheck(String fileCheck) throws NonexistentEntityException {
        try {
            Query q = ds.createQuery(EventLog.class).field("fileCheck").equal(fileCheck);
            EventLog log = (EventLog) q.get();
            return log;
        } catch (Exception e) {
            throw new NonexistentEntityException("The database "
                    + ds.getMongo().getUsedDatabases()
                    + " at " + ds.getMongo().getAddress()
                    + " don't contain any element with filecheck " + fileCheck);
        }
    }

    public List<EventLog> findInProcess() throws NonexistentEntityException {
        try {
            Query<EventLog> q = ds.createQuery(EventLog.class).filter("stateWork =", 0).order("startDate");
            List<EventLog> list = q.asList();
            return list;
        } catch (Exception e) {
            throw new NonexistentEntityException("The database "
                    + ds.getMongo().getUsedDatabases()
                    + " at " + ds.getMongo().getAddress()
                    + " don't contain any element with status= 'IN_PROGRESS'");
        }
    }
}